// i.r(t), i.d(t, { default: () => ViewmodeChange })

import * as THREE from "three"
import { NavigateToSweepCommand } from "../command/navigate.command"
import { ChangeViewmodeCommand } from "../command/viewmode.command"
import configConst from "../constant/config.const"
import ApplicationData from "../data/ApplicationData"
import CameraData from "../data/CameraData"
import CameraStartData from "../data/CameraStartData"
import FloorsViewData from "../data/FloorsViewData"
import MeshData from "../data/MeshData"
import SettingsData from "../data/SettingsData"
import SweepData from "../data/SweepData"
import ViewmodeData from "../data/ViewmodeData"
import EngineContext from "../EngineContext"
import { appTypeMin } from "../enum/appType.enum"
import modeEnum from "../enum/mode.enum"
import optionsKeyEnum from "../enum/optionsKey.enum"
import transitionTypeEnum from "../enum/transitionType.enum"
import viewmodeEnum from "../enum/viewmode.enum"
import g from "../math/51263"
import f from "../math/57051"
import p from "../math/69626"
import { ApplicationChangeMessage } from "../message/app.message"
import SymbolList from "../SymbolList"
import Vectors from "../three/Vectors"
import { isPanOrMesh } from "../utils/viewmode.util"
import CanvasModule from "./CanvasModule"
import Module from "./Module"
import ViewmodeModule from "./ViewmodeModule"
export default class ViewmodeChange extends Module {
  dhDisabled: any
  fpDisabled: any
  engine: EngineContext
  viewmodesModule: ViewmodeModule
  settings: SettingsData
  previousApp: any
  meshData: any
  constructor() {
    super(...arguments)
    this.name = "viewmode-change"
    this.dhDisabled = () => !1
    this.fpDisabled = () => !1
  }
  async init(e, t: EngineContext) {
    this.engine = t
    this.viewmodesModule = await t.getModule(ViewmodeModule)
    this.bindings.push(
      t.subscribe(ApplicationChangeMessage, e => this.setEnabledModes(e.application)),
      t.commandBinder.addBinding(ChangeViewmodeCommand, this.onChangeViewmodeCommand.bind(this))
    )
    Promise.all([t.market.waitForData(ApplicationData), t.market.waitForData(SettingsData)]).then(([e, t]) => {
      this.settings = t
      this.setEnabledModes(e.application)
    })
  }
  async setEnabledModes(e: string) {
    if (e === appTypeMin.SHOWCASE) {
      this.dhDisabled = () => this.settings.checkUrlParam("dh", 0, 1) || !this.settings.tryGetProperty(optionsKeyEnum.Dollhouse, !1)
      this.fpDisabled = () => this.settings.checkUrlParam("fp", 0, 1) || !this.settings.tryGetProperty(optionsKeyEnum.FloorPlan, !1)
      if (!this.previousApp) return
      const e = (await this.engine.market.waitForData(ViewmodeData)).currentMode
      if ((e === viewmodeEnum.Dollhouse && this.dhDisabled()) || (e === viewmodeEnum.Floorplan && this.fpDisabled())) {
        const e = (await this.engine.market.waitForData(CameraStartData)).pose
        if (e && isPanOrMesh(e.mode)) this.goToInsideMode(transitionTypeEnum.Interpolate, { position: e.camera.position }, e.mode)
        else {
          const e = (await this.engine.market.waitForData(CameraData)).pose,
            t = (await this.engine.market.waitForData(SweepData)).getClosestSweep(e.position, !0),
            i = t ? { position: t.position } : void 0
          this.goToInsideMode(transitionTypeEnum.Interpolate, i, viewmodeEnum.Panorama)
        }
      }
    } else e === appTypeMin.WORKSHOP && ((this.dhDisabled = () => !1), (this.fpDisabled = () => !1))
    this.previousApp = e
  }
  async onChangeViewmodeCommand(e) {
    switch (e.mode) {
      case modeEnum.INSIDE:
        return this.goToInsideMode(e.transitionType, e.pose, viewmodeEnum.Panorama)
      case modeEnum.DOLLHOUSE:
        return this.goToDollhouse(e.transitionType, e.pose)
      case modeEnum.FLOORPLAN:
        return this.goToFloorplan(e.transitionType, e.pose)
      case modeEnum.ORTHOGRAPHIC:
        return this.goToOrthographic(e.transitionType, e.pose)
      case modeEnum.MESH:
        return this.goToInsideMode(e.transitionType, e.pose, viewmodeEnum.Mesh)
    }
    return Promise.reject(`viewmode-change => Could not move to ${e.mode}`)
  }
  async goToInsideMode(e = transitionTypeEnum.Interpolate, t: any = {}, i?) {
    const n = this.engine.market.tryGetData(SweepData)
    if (!n) return Promise.reject("Cannot go to inside mode")
    if (!isPanOrMesh(i)) return Promise.reject("Unsupport mode!")
    let s = t.sweepID || n.currentSweep
    if ((s || (s = await this.getLookAtSweep(n)), n.isSweepUnaligned(s))) {
      const e = n.getFirstAlignedSweep()
      s = e ? e.id : this.getFirstSweepId(n)
    }
    return isPanOrMesh(this.viewmodesModule.currentMode) && n.isSweepUnaligned(n.currentSweep)
      ? this.engine.commandBinder.issueCommand(
          new NavigateToSweepCommand({
            sweep: s,
            rotation: t.rotation,
            transition: transitionTypeEnum.FadeToBlack
          })
        )
      : this.viewmodesModule.switchToMode(i, e, { sweepID: s, rotation: t.rotation }, configConst.DEFAULT_TRANSITION_TIME)
  }
  async getLookAtSweep(e) {
    const t = this.engine.market.tryGetData(CameraData)
    if (!t) return this.getFirstSweepId(e)
    const i = this.engine.market.tryGetData(FloorsViewData),
      n = (null == i ? void 0 : i.getFloorMin()) || this.getModelMinHeight(),
      s = new THREE.Plane(Vectors.DOWN, n),
      r = p.Fe(t.pose.position, t.pose.rotation, s)
    if (!r) return this.getFirstSweepId(e)
    const o = [g._T(), g._k(), e => !i || i.isCurrentOrAllFloors(e.floorId)],
      a = [f.l0(r)],
      l = e.sortByScore(o, a).shift()
    if (l) return l.sweep.id
    const c = e.getClosestSweep(r, !0)
    return c ? c.id : this.getFirstSweepId(e)
  }
  getFirstSweepId(e) {
    const t = e.getFirstSweep()
    if (void 0 === t) throw new Error("First enabled sweep not found")
    return t.id
  }
  getModelMinHeight() {
    return this.meshData || (this.meshData = this.engine.market.tryGetData(MeshData)), this.meshData ? this.meshData.bounds.min.y : 0
  }
  async goToDollhouse(e = transitionTypeEnum.Interpolate, t = {}) {
    return this.dhDisabled() ? Promise.reject("Cannot go to dollhouse mode") : this.viewmodesModule.switchToMode(viewmodeEnum.Dollhouse, e, t)
  }
  async goToFloorplan(e = transitionTypeEnum.Interpolate, t = {}) {
    if (this.fpDisabled()) return Promise.reject("Cannot go to floorplan mode")
    const i = await this.engine.getModuleBySymbol<CanvasModule>(SymbolList.CANVAS)
    return i && (await i.getTransitionPromise()), this.viewmodesModule.switchToMode(viewmodeEnum.Floorplan, e, t)
  }
  async goToOrthographic(e = transitionTypeEnum.Interpolate, t = {}) {
    const i = await this.engine.getModuleBySymbol<CanvasModule>(SymbolList.CANVAS)
    return i && (await i.getTransitionPromise()), this.viewmodesModule.switchToMode(viewmodeEnum.Orthographic, e, t)
  }
}
